import os
import re
import json
import time
import uvicorn
import requests
from urllib.parse import quote
from difflib import SequenceMatcher

from PIL import Image
from io import BytesIO
from sys import getsizeof
from ddddocr import DdddOcr
from base64 import b64decode, b64encode
from fastapi import Body, Query, FastAPI, Request, HTTPException
from fastapi.responses import Response, HTMLResponse, FileResponse, RedirectResponse, StreamingResponse
from spiders import SPIDERS
from danmuku import handleDanmu, handleStream

# OCR相关
def handleOcr(img: bytes, comp, lenth):
    retry = 1
    ocr = DdddOcr(show_ad=False)
    while retry < 5:
        result = ocr.classification(img)
        if comp == 'digit':
            if result.isdigit():
                if lenth != 0:
                    if len(result) == lenth:
                        break
                else:
                    break
        elif comp == 'alpha':
            if result.isalpha():
                if lenth != 0:
                    if len(result) == lenth:
                        break
                else:
                    break
        elif comp == 'alnum':
            if result.isalnum():
                if lenth != 0:
                    if len(result) == lenth:
                        break
                else:
                    break
        else:
            raise ValueError("识别结果格式或位数错误")
        retry += 1
    return result

def handleDet(img: bytes):
    det = DdddOcr(det=True, show_ad=False)
    return det.detection(img)

def handleCrop(img):
    imgByte = BytesIO()
    img.save(imgByte, format='PNG', subsampling=0, quality=100)
    imgByte = imgByte.getvalue()
    return imgByte

def handleSlide(targetImg: bytes, backgroundImg: bytes):
    slide = DdddOcr(det=False, ocr=False, show_ad=False)
    if len(backgroundImg) == 0:
        imageStream = BytesIO(targetImg)
        imageFile = Image.open(imageStream)
        backgroundImg = imageFile.crop((0, 300, 240, 450))
        cropped = imageFile.crop((0, 0, 240, 150))
        return slide.slide_comparison(handleCrop(cropped), handleCrop(backgroundImg))
    else:
        return slide.slide_match(targetImg, backgroundImg, simple_target=True)

# 开始FastAPI及相关设置
temp = {}
cache = {}
PythonT4 = FastAPI()
# 提供 index.html 文件
@PythonT4.get("/", response_class=HTMLResponse)
def index():
    return FileResponse("templates/index.html")

@PythonT4.get("/PythonT4", response_class=HTMLResponse)
def indexT4(wallpaper: str = Query('http://饭太硬.top/深色壁纸/api.php'), alitoken: str = Query('http://127.0.0.1:9978/file/tvfan/alitoken'), thread: str = Query('10'), liveurl: str = Query("http://127.0.0.1:9978/file/tvfan/live.json"), bilijson: str = Query('http://127.0.0.1:9978/file/tvfan/bili.json'), alistjson: str = Query('http://127.0.0.1:9978/file/tvfan/alist.json'), liveinfoUrl : str = Query('https://fanty.run.goorm.site/live.txt'), liveinfoPlayerType: int = Query(1), liveinfoUa : str = Query('okhttp/3.15')):
    data = {'spider': '', 'wallpaper': wallpaper, 'sites': [{'key': 'py_ali', 'name': '首页', 'type': 3, 'api': 'https://api-lmteam.koyeb.app/files/py/py_ali.py', 'searchable': 1, 'quickSearch': 1, 'filterable': 1, 'ext': {'token': alitoken, 'thread': thread}}, {'key': 'py_cntv', 'name': '央视', 'type': 3, 'api': 'https://api-lmteam.koyeb.app/files/py/py_cntv.py', 'searchable': 0, 'quickSearch': 0, 'filterable': 1}, {'key': 'py_live', 'name': '直播', 'type': 3, 'api': 'https://api-lmteam.koyeb.app/files/py/py_live.py', 'searchable': 0, 'quickSearch': 0, 'filterable': 1, 'ext': {'url': liveurl}}, {'key': 'py_bilibilivd', 'name': 'B站视频', 'type': 3, "style": {"type": "rect", "ratio": 1.43}, 'api': 'https://api-lmteam.koyeb.app/files/py/py_bilibilivd.py', 'searchable': 1, 'quickSearch': 1, 'filterable': 1, 'ext': {'json': bilijson}}, {'key': 'py_bilibilimd', 'name': 'B站番剧', 'type': 3, 'api': 'https://api-lmteam.koyeb.app/files/py/py_bilibilimd.py', 'searchable': 1, 'quickSearch': 1, 'filterable': 1, 'ext': {'json': bilijson}}, {'key': 'py_firstaid', 'name': '急救指南', 'type': 3, 'api': 'https://api-lmteam.koyeb.app/files/py/py_firstaid.py', 'searchable': 0, 'quickSearch': 0, 'filterable': 0}, {'key': 'py_sport', 'name': '体育直播', 'type': 3, 'api': 'https://api-lmteam.koyeb.app/files/py/py_sport.py', 'searchable': 0, 'quickSearch': 0, 'filterable': 0}, {'key': 'py_alist', 'name': 'Alist网盘', 'type': 3, 'api': 'https://api-lmteam.koyeb.app/files/py/py_alist.py', 'searchable': 0, 'quickSearch': 0, 'filterable': 0, 'ext': alistjson}], 'parses': [{'name': '聚合', 'type': 3, 'url': 'Demo'}, {'name': '神秘的哥哥们', 'type': 1, 'url': 'http://api.888484.xyz/神秘哥哥/super.php?v=', 'ext': {'flag': ['qq', '腾讯', 'qiyi', '爱奇艺', '奇艺', 'youku', '优酷', 'tucheng', 'sohu', '搜狐', 'letv', '乐视', 'mgtv', '芒果', 'tnmb', 'seven', 'yzm', 'aliyun', 'RJuMao', 'bilibili', '1905', 'xinvip', 'XAL', 'qiqi', 'XALS', 'YuMi-vip']}}, {'name': '免费分享', 'type': 0, 'url': 'https://jx.xmflv.com/?url=', 'ext': {'flag': ['qq', '腾讯', 'qiyi', '爱奇艺', '奇艺', 'youku', '优酷', 'mgtv', '芒果', 'imgo', 'letv', '乐视', 'pptv', 'PPTV', 'sohu', 'bilibili', '哔哩哔哩', '哔哩'], 'header': {'User-Agent': 'okhttp/4.1.0'}}}], 'doh': [{'name': 'Google', 'url': 'https://dns.google/dns-query', 'ips': ['8.8.4.4', '8.8.8.8']}, {'name': 'Cloudflare', 'url': 'https://cloudflare-dns.com/dns-query', 'ips': ['1.1.1.1', '1.0.0.1', '2606:4700:4700::1111', '2606:4700:4700::1001']}, {'name': 'AdGuard', 'url': 'https://dns.adguard.com/dns-query', 'ips': ['94.140.14.140', '94.140.14.141']}, {'name': 'DNSWatch', 'url': 'https://resolver2.dns.watch/dns-query', 'ips': ['84.200.69.80', '84.200.70.40']}, {'name': 'Quad9', 'url': 'https://dns.quad9.net/dns-quer', 'ips': ['9.9.9.9', '149.112.112.112']}], 'rules': [{'name': 'hwk', 'hosts': ['haiwaikan'], 'regex': ['10.0099', '10.3333', '16.0599', '8.1748', '10.85']}, {'name': 'yqk', 'hosts': ['yqk88'], 'regex': ['18.4', '15.1666']}, {'name': 'sn', 'hosts': ['suonizy'], 'regex': ['15.1666', '15.2666']}, {'name': 'bf', 'hosts': ['bfzy'], 'regex': ['#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:3,[\\s\\S]*?#EXT-X-DISCONTINUITY']}, {'name': 'xx', 'hosts': ['aws.ulivetv.net'], 'regex': ['#EXT-X-DISCONTINUITY\\r*\\n*#EXTINF:8,[\\s\\S]*?#EXT-X-DISCONTINUITY']}, {'name': 'lz', 'hosts': ['vip.lz', 'hd.lz', 'v.cdnlz1', 'v.cdnlz'], 'regex': ['18.5333']}, {'name': '非凡', 'hosts': ['vip.ffzy', 'hd.ffzy'], 'regex': ['25.0666']}, {'name': 'hs', 'hosts': ['huoshan.com'], 'regex': ['item_id=']}, {'name': 'dy', 'hosts': ['douyin.com'], 'regex': ['is_play_url=']}, {'name': 'nm', 'hosts': ['toutiaovod.com'], 'regex': ['video/tos/cn']}, {'name': 'cl', 'hosts': ['magnet'], 'regex': ['最新', '直播', '更新']}], 'lives': [{'name': 'live', 'type': 0, 'url': liveinfoUrl, 'playerType': liveinfoPlayerType, 'ua': liveinfoUa, 'epg': 'http://epg.112114.xyz/?ch={name}&date={date}', 'logo': 'https://epg.112114.xyz/logo/{name}.png'}]}
    return Response(content=json.dumps(data, ensure_ascii=False).encode(), media_type="text/plain")

@PythonT4.get("/files/{filePath:path}", response_class=HTMLResponse)
def downloadFile(filePath: str):
    pos = filePath.rfind('/')
    if pos == -1:
        path = ''
    else:
        path = filePath[:pos]
    content = f"""<!DOCTYPE html>
<html>
  <head>
    <title>文件</title>
  </head>
  <body>
  <h1>文件</h1><hr><pre><a href="/files/{path}" style="font-size: 20px; text-decoration: none;">返回上级目录</a>\n"""
    filePath = 'files/{}'.format(filePath)
    infoList = []
    if os.path.isdir(filePath):
        fileList = os.listdir(filePath)
    else:
        return FileResponse(filePath)
    for file in fileList:
        if os.path.isdir(filePath+'/'+file):
            type = 0
        else:
            type = 1
        infoList.append({'name': file, 'type': type})
    infoList = sorted(infoList, key=lambda x: x['type'])
    for info in infoList:
        content += '<a href=/{}/{} style="font-size: 20px; text-decoration: none;" >{}</a>\n'.format(filePath, info['name'], info['name']).replace('//', '/')
    content += """  </pre><hr></body>
</html>"""
    return content

# 设置网页图标
@PythonT4.get("/favicon.ico")
def favicon():
    return FileResponse("templates/favicon.ico")

# PythonT4弹幕
@PythonT4.get("/danmu")
def danmu(params: str):
    try:
        global temp
        tempkey = params
        params = json.loads(params)

        def getContent(tempkey, params):
            global temp
            content = ''
            starttime = int(time.time())
            for line in handleStream(params):
                yield (line + '\n').encode()
                content = content + line + '\n'
                if line == '</i>':
                    tempSize = getsizeof(temp)
                    if tempSize >= 134217728:
                        temp = {}
                    temp.update({tempkey: {'content': content, 'expires_at': int(time.time()) + 14400}})
                    break
                if int(time.time()) - starttime >= 600:
                    break

        if tempkey in temp:
            if temp[tempkey]['expires_at'] >= int(time.time()):
                content = temp[tempkey]['content']
                return Response(content=content, media_type="text/xml")
            else:
                del temp[tempkey]
                content, stream = handleDanmu(params)
                if stream:
                    return StreamingResponse(getContent(tempkey, params), 200, {'Content-Type': 'text/xml'})
                else:
                    tempSize = getsizeof(temp)
                    if tempSize >= 134217728:
                        temp = {}
                    temp.update({tempkey: {'content': content, 'expires_at': int(time.time()) + 14400}})
                    return Response(content=content, media_type="text/xml")
        else:
            content, stream = handleDanmu(params)
            if stream:
                return StreamingResponse(getContent(tempkey, params), 200, {'Content-Type': 'text/xml'})
            else:
                tempSize = getsizeof(temp)
                if tempSize >= 134217728:
                    temp = {}
                temp.update({tempkey: {'content': content, 'expires_at': int(time.time()) + 14400}})
                return Response(content=content, media_type="text/xml")
    except Exception as e:
        raise HTTPException(status_code=404, detail="错误：{}".format(e))

# PythonT4搜索弹幕
@PythonT4.get("/searchdm")
def searchdm(params: str):
    params = json.loads(params)
    pos = params['pos']
    name = params['name']
    try:
        diffList = []
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
            'Referer': 'https://www.iqiyi.com/'
        }
        r = requests.get('https://suggest.video.iqiyi.com/', headers=header, params={'key': name})
        dataList = r.json()
        for data in dataList['data']:
            diffList.append({'ratio': SequenceMatcher(None, data['name'], name).ratio(), "content": data['name']})
        diffList = sorted(diffList, key=lambda x: x['ratio'], reverse=True)
        keyword = diffList[0]['content']
    except:
        keyword = name
    url = ''
    pos = int(pos)
    pos = pos - 1
    if pos < 0:
        pos = 0
    try:
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36'
        }
        r = requests.get(f'http://aliys.cn:90/api.php/provide/vod?wd={quote(keyword)}&ac=detail', headers=header, timeout=5)
        vodList = r.json()['list']

        if 'regSrc' in params:
            regSrc = str(params['regSrc'])
        else:
            regSrc = None
        if 'videoType' in params:
            videoType = params['videoType']
        else:
            videoType = None

        breakSignal = False
        if videoType:
            for vod in vodList:
                if videoType != vod['type_name']:
                    continue
                infosList = vod['vod_play_url'].strip().split('#')
                if regSrc:
                    for infos in infosList:
                        try:
                            lenRegSrc = len(regSrc)
                            regResult = str(int(''.join(re.findall(r'\d+', infos.split('$')[0]))))
                            lenRegResult = len(regResult)
                            if lenRegResult > lenRegSrc:
                                regResult = regResult[lenRegSrc:]
                            else:
                                regResult = regResult.zfill(lenRegSrc)
                        except:
                            regResult = ''
                        if regResult == regSrc:
                            url = infos.split('$')[1]
                            breakSignal = True
                            break
                if breakSignal:
                    break
                else:
                    try:
                        url = infosList[pos].split('$')[1]
                        break
                    except:
                        pass

        else:
            diffList = []
            for vod in vodList:
                diffList.append({"ratio": SequenceMatcher(None, vod['vod_name'], name).ratio(), "content": vod})
            diffList = sorted(diffList, key=lambda x: x['ratio'], reverse=True)
            for diff in diffList:
                vod = diff['content']
                infosList = vod['vod_play_url'].strip().split('#')
                if regSrc:
                    for infos in infosList:
                        try:
                            lenRegSrc = len(regSrc)
                            regResult = str(int(''.join(re.findall(r'\d+', infos.split('$')[0]))))
                            lenRegResult = len(regResult)
                            if lenRegResult > lenRegSrc:
                                regResult = regResult[lenRegSrc:]
                            else:
                                regResult = regResult.zfill(lenRegSrc)
                        except:
                            regResult = ''
                        if regResult == regSrc:
                            url = infos.split('$')[1]
                            breakSignal = True
                            break
                if breakSignal:
                    break
                else:
                    try:
                        url = infosList[pos].split('$')[1]
                        break
                    except:
                        pass

        if 'qq.com' in url:
            params = {'platform': 'qq', 'url': url}
        elif 'mgtv.com' in url:
            params = {'platform': 'mgtv', 'url': url}
        elif 'iqiyi.com' in url:
            params = {'platform': 'iqiyi', 'url': url}
        elif 'youku.com' in url:
            params = {'platform': 'youku', 'url': url}
        elif 'bilibili.com' in url:
            params = {'platform': 'bilibili', 'url': url}
        else:
            content = f"未找到影片{name}"
            return Response(status_code=404, content=content, media_type="text/plain")
        return Response(content=json.dumps(params), media_type="text/plain")
    except Exception as e:
        raise HTTPException(status_code=404, detail="错误：{}".format(e))

# 设置缓存
@PythonT4.post("/cache")
async def setCache(request: Request, key: str):
    value = await request.body()
    cache[key] = value

# 获取缓存
@PythonT4.get("/cache")
async def getCache(key: str):
    if key not in cache:
        return Response(content='', media_type="text/plain")
    try:
        if type(cache[key]) == dict or type(cache[key]) == list:
            content = json.dumps(cache[key])
        else:
            content = cache[key]
        return Response(content=content, media_type="text/plain")
    except Exception as e:
        raise HTTPException(status_code=404, detail="错误：{}".format(e))

# 删除缓存
@PythonT4.delete("/cache")
async def deleteCache(key: str):
    if key not in cache:
        raise HTTPException(status_code=404, detail="无法删除，未找到缓存{}".format(key))
    del cache[key]

# ocr 处理
# @PythonT4.post("/ocr")
def ocr(data: dict = Body(...)):
    cookies = {}
    backgroundImgdata = bytes()
    # 获取验证码及所需headers
    if 'header' in data:
        header = data['header']
    else:
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36'
        }
    if 'urlList' in data:
        # 为url则下载并获取cookies
        urlList = data['urlList']
        try:
            if len(urlList) == 1:
                r = requests.get(urlList[0], headers=header, timeout=30)
                for key, value in r.cookies.items():
                    cookies.update({key: value})
                imgdata = r.content
            else:
                imgdata = requests.get(urlList[0], headers=header, timeout=30).content
                backgroundImgdata = requests.get(urlList[1], headers=header, timeout=30).content
        except:
            return {'code': 0, 'result': None, 'msg': '访问{}超时'.format(urlList)}
    elif 'imgList' in data:
        # 为imgList中为imgs的base64解码
        imgList = data['imgList']
        if len(imgList) == 1:
            imgdata = imgList[0]
            if imgdata.startswith('data'):
                imgdata = imgdata.split(',', 1)[1]
            imgdata = b64decode(imgdata)
        else:
            imgdata = imgList[0]
            if imgdata.startswith('data'):
                imgdata = imgdata.split(',', 1)[1]
            imgdata = b64decode(imgdata)
            backgroundImgdata = imgList[1]
            if backgroundImgdata.startswith('data'):
                backgroundImgdata = backgroundImgdata.split(',', 1)[1]
            backgroundImgdata = b64decode(backgroundImgdata)
    else:
        return {'code': 0, 'result': None, 'msg': '没有图片'}
    # 获取ocrType。1：ocr，2：点选，3：滑块。
    if 'ocrType' in data:
        ocrType = data['ocrType']
    else:
        ocrType = 1
    # 获取comp参数，digit-纯数字、alpha-纯字母、alnum-数字和字母
    if 'comp' in data:
        comp = data['comp']
        if comp not in ['digit', 'alpha', 'alnum']:
            comp = 'alnum'
    else:
        comp = 'alnum'
    # 获取lenth参数
    if 'lenth' in data:
        lenth = data['lenth']
        if not lenth.isdigit():
            lenth = 0
        else:
            lenth = int(lenth)
    else:
        lenth = 0
    try:
        if ocrType == 1:
            result = handleOcr(imgdata, comp, lenth)
        elif ocrType == 2:
            result = handleDet(imgdata)
        elif ocrType == 3:
            result = handleSlide(imgdata, backgroundImgdata)
        else:
            return {'code': 0, 'result': None, 'msg': '失败'}
        if not 'urlList' in data or cookies == {}:
            return {'code': 1, 'result': result, 'msg': 'success'}
        else:
            return {'code': 1, 'cookies': cookies, 'result': result, 'msg': 'success'}
    except Exception as e:
        return {'code': 0, 'result': None, 'msg': str(e).strip()}

# img 处理
# @PythonT4.post("/rebuildimg")
def rebuildImg(data: dict = Body(...)):
    cookies = {}
    if 'header' in data:
        header = data['header']
    else:
        header = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.54 Safari/537.36'
        }
    if 'imgUrl' in data:
        url = data['imgUrl']
        try:
            r = requests.get(url, headers=header, timeout=30)
            for key, value in r.cookies.items():
                cookies.update({key: value})
            imgData = r.content
        except:
            return {'code': 0, 'result': None, 'msg': '访问{}超时'.format(url)}
    elif 'imgData' in data:
        imgData = data['imgData']
        if imgData.startswith('data'):
            imgData = imgData.split(',', 1)[1]
        imgData = b64decode(imgData)
    else:
        return {'code': 0, 'result': None, 'msg': '没有图片'}
    if 'offsetsDict' in data:
        offsetsDict = data['offsetsDict']
    else:
        return {'code': 0, 'result': None, 'msg': '缺少offsetsList参数'}
    if 'whList' in data:
        whList = data['whList']
    else:
        return {'code': 0, 'result': None, 'msg': 'whList'}
    try:
        weight, height = whList
        imgStream = BytesIO(imgData)
        imgFile = Image.open(imgStream)
        newimgFile = Image.new('RGB', (260, 116))
        if 'upper' in offsetsDict:
            i = 0
            for offset in offsetsDict['upper']:
                offset = (int(offset[0]), int(offset[1]), int(offset[0]) + int(weight), int(offset[1]) + int(height))
                newoffset = (0 + i, 0)
                i += int(weight)
                region = imgFile.crop(offset)
                newimgFile.paste(region, newoffset)
        if 'lower' in offsetsDict:
            i = 0
            for offset in offsetsDict['lower']:
                offset = (int(offset[0]), int(offset[1]), int(offset[0]) + int(weight), int(offset[1]) + int(height))
                newoffset = (0 + i, int(height))
                i += int(weight)
                region = imgFile.crop(offset)
                newimgFile.paste(region, newoffset)
        imgFile = BytesIO()
        newimgFile.save(imgFile, format="PNG")
        imgData = b64encode(imgFile.getvalue()).decode()
        if not 'imgUrl' in data or cookies == {}:
            return {'code': 1, 'result': imgData, 'msg': 'success'}
        else:
            return {'code': 1, 'cookies': cookies, 'result': imgData, 'msg': 'success'}
    except Exception as e:
        return {'code': 0, 'result': None, 'msg': str(e).strip()}

# 直播处理
@PythonT4.get("/live/{site}")
@PythonT4.post("/live/{site}")
def live(request: Request, site: str, params: str):
    try:
        params = json.loads(params)
        if request.url.port:
            localUrl = '{}://{}:{}'.format(request.url.scheme, request.url.hostname, request.url.port)
        else:
            localUrl = '{}://{}'.format(request.url.scheme, request.url.hostname)
        cache['localUrl'] = localUrl
        playUrl = SPIDERS[site.upper()].getInfos(params)
        return RedirectResponse(url=playUrl)
    except Exception as e:
        raise HTTPException(status_code=404, detail="错误：{}".format(e))

# 点播处理
@PythonT4.get("/PythonT4/{site}")
@PythonT4.post("/PythonT4/{site}")
def pythonT4(request: Request, site: str, t: str = Query(''), ac: str = Query(''), wd: str = Query(''), pg: int = Query(1), ids: str = Query(''), play: str = Query(''), flag: str = Query(''), ext: str = Query('e30%3D'), extend: str = Query('{}'), quick: bool = Query(False), filter: bool = Query(False)):
    if request.url.port:
        localUrl = '{}://{}:{}'.format(request.url.scheme, request.url.hostname, request.url.port)
    else:
        localUrl = '{}://{}'.format(request.url.scheme, request.url.hostname)
    cache['localUrl'] = localUrl
    if ext == '':
        ext = 'e30%3D'
    params = {
        't': t,
        'ac': ac,
        'wd': wd,
        'pg': pg,
        'ids': ids,
        'ext': ext,
        'play': play,
        'flag': flag,
        'extend': extend,
        'quick': quick,
        'filter': filter
    }
    try:
        global temp
        tempkey = site.lower()
        for param in params:
            if param == 'extend':
                continue
            tempkey = tempkey + "_" + str(params[param])
        if tempkey in temp:
            if temp[tempkey]['expires_at'] >= int(time.time()):
                content = temp[tempkey]['content']
            else:
                del temp[tempkey]
                content, expire = SPIDERS[site.upper()].getInfo(params)
                tempSize = getsizeof(temp)
                if tempSize >= 134217728:
                    temp = {}
                temp.update({tempkey: {'content': content, 'expires_at': int(time.time()) + expire}})
        else:
            content, expire = SPIDERS[site.upper()].getInfo(params)
            tempSize = getsizeof(temp)
            if tempSize >= 134217728:
                temp = {}
            temp.update({tempkey: {'content': content, 'expires_at': int(time.time()) + expire}})
    except Exception as e:
        raise HTTPException(status_code=404, detail="错误：{}".format(e))
    return Response(content=json.dumps(content, ensure_ascii=False).encode(), media_type="text/plain")

# PythonT4代理
@PythonT4.get("/proxy")
def proxy(request: Request, spider: str, function: str, params: str):
    if request.url.port:
        localUrl = '{}://{}:{}'.format(request.url.scheme, request.url.hostname, request.url.port)
    else:
        localUrl = '{}://{}'.format(request.url.scheme, request.url.hostname)
    cache['localUrl'] = localUrl
    try:
        params = json.loads(params)
        content, mediaType, status = getattr(SPIDERS[spider.upper()], function)(params)
        if status == 302:
            return RedirectResponse(url=content)
        return Response(content=content, media_type=mediaType)
    except Exception as e:
        raise HTTPException(status_code=404, detail="错误：{}".format(e))

# 以8000端口启动服务
uvicorn.run(PythonT4, host="0.0.0.0", port=8000, reload=False)
